import pandas as pd
import thostmduserapi as mdapi
from datetime import time
import time as tm
import socket
import json

'''需要订阅的合约list'''

# fut_list = pd.read_csv("../fut_list/all_futures.csv")
# fut_list = fut_list[(fut_list.end_date >= "20201102") & (fut_list.start_date <= "20201102")]
# fut_list = fut_list['name'].values.tolist()
# subID = fut_list

subID = ["IF2012"]
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

class CBarData:
    def __init__(self):
        self.instrumentID: str
        self.updateTime: time
        self.volume: float = 0
        self.openInterest: float = 0
        self.openPrice: float = 0
        self.highPrice: float = 0
        self.lowPrice: float = 0
        self.closePrice: float = 0

# 继承自spi基类mdapi.CThostFtdcMdSpi
class CFtdcMdSpi(mdapi.CThostFtdcMdSpi):

    def __init__(self, tapi):
        mdapi.CThostFtdcMdSpi.__init__(self)
        self.tapi = tapi
        self.bar = None
        # self.lastVolume: double = 0
        self.submap = {}

        self.data_dict = {}
        self.lastVolume = {}

    def OnFrontConnected(self) -> "void":
        print("OnFrontConnected")
        loginfield = mdapi.CThostFtdcReqUserLoginField()
        loginfield.BrokerID = "9999"
        loginfield.UserID = "171525"
        loginfield.Password = "1234qwer@"
        loginfield.UserProductInfo = "python dll"
        # 实现onfrontconnect函数，在里面调用登录，第7步
        self.tapi.ReqUserLogin(loginfield, 0)

    def OnRspUserLogin(self, pRspUserLogin: 'CThostFtdcRspUserLoginField', pRspInfo: 'CThostFtdcRspInfoField',
                       nRequestID: 'int', bIsLast: 'bool') -> "void":
        print(f"OnRspUserLogin, SessionID={pRspUserLogin.SessionID},ErrorID={pRspInfo.ErrorID},ErrorMsg={pRspInfo.ErrorMsg}")
        # 继承实现登录回调，登录成功后去订阅，第9步
        ret = self.tapi.SubscribeMarketData([id.encode('utf-8') for id in subID], len(subID))

    def OnRtnDepthMarketData(self, pDepthMarketData: 'CThostFtdcDepthMarketDataField') -> "void":
        # 继承收取订阅行情，第11步,在这里将pDepthMarketData数据存入csv即可录得数据
        # print(f"InstrumentID={pDepthMarketData.InstrumentID},LastPrice={pDepthMarketData.LastPrice}")
        # 根据行情中的UpdateTime字段判断是否为新1分钟
        st = pDepthMarketData.UpdateTime.split(':')

        name = pDepthMarketData.InstrumentID
        if not self.data_dict.get(name):
            self.data_dict[name] = {}
            self.data_dict[name]['minite'] = int(st[1])
            self.data_dict[name]['bar'] = None
            self.data_dict[name]['list'] = {}
            self.data_dict[name]['list']['date'] = []
            self.data_dict[name]['list']['open'] = []
            self.data_dict[name]['list']['high'] = []
            self.data_dict[name]['list']['low'] = []
            self.data_dict[name]['list']['close'] = []

        '''
        if not self.bar:
            newMinitue = True
            print('TTTTTTTTTTTTTT')
        else:
            if int(st[1]) == self.bar.updateTime.minute:
                newMinitue = False
                print('FFFFFFFFFFFFFFFFF')
            else:
                newMinitue = True
                print('111111111111111111111')
        '''

        if self.data_dict[name]['minite'] == int(st[1]) and self.data_dict[name]['bar'] is not None:
            newMinitue = False
            # print('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')

        else:
            newMinitue = True
            print('+++++++++++++++++++++++++++++++++++++++++++++++++++++')
        if newMinitue:
            try:
                print(f"InstrumentID={pDepthMarketData.InstrumentID},LastPrice={pDepthMarketData.LastPrice}")
                self.data_dict[name]['list']['date'].append(f"{tm.strftime('%Y-%m-%d')}" + " " + f"{self.data_dict[name]['bar'].updateTime}")
                if len(self.data_dict[name]['list']['date']) >= 60:
                    self.data_dict[name]['list']['date'] = self.data_dict[name]['list']['date'][-61:]
                self.data_dict[name]['list']['open'].append(float(f"{self.data_dict[name]['bar'].openPrice}"))
                if len(self.data_dict[name]['list']['open']) >= 60:
                    self.data_dict[name]['list']['open'] = self.data_dict[name]['list']['open'][-61:]
                self.data_dict[name]['list']['high'].append(float(f"{self.data_dict[name]['bar'].highPrice}"))
                if len(self.data_dict[name]['list']['high']) >= 60:
                    self.data_dict[name]['list']['high'] = self.data_dict[name]['list']['high'][-61:]
                self.data_dict[name]['list']['low'].append(float(f"{self.data_dict[name]['bar'].lowPrice}"))
                if len(self.data_dict[name]['list']['low']) >= 60:
                    self.data_dict[name]['list']['low'] = self.data_dict[name]['list']['low'][-61:]
                self.data_dict[name]['list']['close'].append(float(f"{self.data_dict[name]['bar'].closePrice}"))
                if len(self.data_dict[name]['list']['close']) >= 60:
                    self.data_dict[name]['list']['close'] = self.data_dict[name]['list']['close'][-61:]
                print(self.data_dict[name]['list'])
                send_data = json.dumps(self.data_dict[name]['list'])
                udp_socket.sendto(send_data.encode('utf-8'), ("127.0.0.1", 8080))

            except:
                pass

            self.data_dict[name]['bar'] = CBarData()
            self.data_dict[name]['bar'].instrumentID = pDepthMarketData.InstrumentID
            self.data_dict[name]['bar'].exchangeID = pDepthMarketData.ExchangeID
            self.data_dict[name]['bar'].updateTime = time(int(st[0]), int(st[1]), 0, 0)
            self.data_dict[name]['bar'].volume = 0
            self.data_dict[name]['bar'].openInterest = pDepthMarketData.OpenInterest
            self.data_dict[name]['minite'] = time(int(st[0]), int(st[1]), 0, 0).minute

            self.data_dict[name]['bar'].openPrice = pDepthMarketData.LastPrice
            self.data_dict[name]['bar'].highPrice = pDepthMarketData.LastPrice
            self.data_dict[name]['bar'].lowPrice = pDepthMarketData.LastPrice
            self.data_dict[name]['bar'].closePrice = pDepthMarketData.LastPrice
        else:
            self.data_dict[name]['bar'].highPrice = max(self.data_dict[name]['bar'].highPrice,
                                                        pDepthMarketData.LastPrice)
            self.data_dict[name]['bar'].lowPrice = min(self.data_dict[name]['bar'].lowPrice, pDepthMarketData.LastPrice)
            self.data_dict[name]['bar'].closePrice = pDepthMarketData.LastPrice
            self.data_dict[name]['bar'].openInterest = pDepthMarketData.OpenInterest

        '''      
        # 如果是新1分钟，生成一个新k线变量，CBarData结构体中有OHLC,time等K线字段
        if newMinitue:
            self.bar = CBarData()
            self.bar.instrumentID = pDepthMarketData.InstrumentID
            self.bar.exchangeID = pDepthMarketData.ExchangeID
            self.bar.updateTime = time(int(st[0]), int(st[1]), 0, 0)
            self.bar.volume = 0
            self.bar.openInterest = pDepthMarketData.OpenInterest

            self.bar.openPrice = pDepthMarketData.LastPrice
            self.bar.highPrice = pDepthMarketData.LastPrice
            self.bar.lowPrice = pDepthMarketData.LastPrice
            self.bar.closePrice = pDepthMarketData.LastPrice
        else:
            # 如果不是新1分钟，将最新价与HL价相比然后更新，跟新C价
            self.bar.highPrice = max(self.bar.highPrice, pDepthMarketData.LastPrice)
            self.bar.lowPrice = min(self.bar.lowPrice, pDepthMarketData.LastPrice)
            self.bar.closePrice = pDepthMarketData.LastPrice
            self.bar.openInterest = pDepthMarketData.OpenInterest

        # 注意Volume字段是累计成交量，所以这个时间段内成交量为该值与上一时间段末成交量的差值
        if not self.lastVolume:
            self.bar.volume += max(pDepthMarketData.Volume - self.lastVolume, 0)
        self.lastVolume = pDepthMarketData.Volume
        '''
        if self.lastVolume.get(name):
            self.data_dict[name]['bar'].volume += max(pDepthMarketData.Volume - self.lastVolume[name], 0)
        self.lastVolume[name] = pDepthMarketData.Volume


def main():
    mduserapi = mdapi.CThostFtdcMdApi_CreateFtdcMdApi()  # 第1步
    mduserspi = CFtdcMdSpi(mduserapi)  # 第2步
    '''以下是生产环境'''
    # mduserapi.RegisterFront("tcp://180.168.146.187:10101")  #第3步
    '''以下是7*24小时环境'''
    mduserapi.RegisterFront("tcp://218.202.237.33:10112")
    mduserapi.RegisterSpi(mduserspi)  # 第4步
    mduserapi.Init()  # 第5步，API正式启动，dll底层会自动去连上面注册的地址
    mduserapi.Join()  # join的目的是为了阻塞主线程，可以用sleep代替


if __name__ == '__main__':
    main()